package utils

import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	config2 "go-pan/internal/config"
	"go-pan/internal/log"
	"go-pan/internal/model"
	"time"

	jwt "github.com/golang-jwt/jwt/v5"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// GenerateRefreshToken 生成无状态的refresh token（使用JWT）
func GenerateRefreshToken(userID int64, username string) (string, error) {
	cfg := config2.GetConfig()
	refreshExpiration := time.Duration(cfg.JWT.RefreshExpiration) * time.Hour

	claims := jwt.MapClaims{
		"user_id":  userID,
		"username": username,
		"type":     "refresh", // 标识这是 refresh token
		"exp":      time.Now().Add(refreshExpiration).Unix(),
		"iat":      time.Now().Unix(),
		"iss":      "go-pan",
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(GetJWTSecret())
}

// ValidateRefreshToken 验证refresh token并提取用户信息
func ValidateRefreshToken(refreshToken string) (userID int64, username string, err error) {
	token, err := jwt.Parse(refreshToken, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return GetJWTSecret(), nil
	})

	if err != nil {
		return 0, "", fmt.Errorf("failed to parse refresh token: %w", err)
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		// 验证 token 类型
		if tokenType, ok := claims["type"].(string); !ok || tokenType != "refresh" {
			return 0, "", errors.New("invalid token type")
		}

		// 提取用户信息
		uid, ok := claims["user_id"].(float64)
		if !ok {
			return 0, "", errors.New("invalid user_id in token")
		}
		userID = int64(uid)

		username, ok = claims["username"].(string)
		if !ok {
			return 0, "", errors.New("invalid username in token")
		}

		return userID, username, nil
	}

	return 0, "", errors.New("invalid refresh token")
}

// RevokeRefreshToken 撤销refresh token（无状态token无法真正撤销，这里加入黑名单）
// 注意：无状态的refresh token无法主动撤销，只能加入黑名单等待过期
func RevokeRefreshToken(refreshToken string) error {
	// 解析token获取过期时间
	token, err := jwt.Parse(refreshToken, func(token *jwt.Token) (interface{}, error) {
		return GetJWTSecret(), nil
	})
	if err != nil {
		return err
	}

	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return errors.New("invalid token claims")
	}

	// 获取过期时间
	var expiration time.Duration
	if exp, ok := claims["exp"].(float64); ok {
		expiration = time.Until(time.Unix(int64(exp), 0))
		if expiration < 0 {
			expiration = 0
		}
	} else {
		// 如果没有过期时间，设置一个较短的过期时间（1小时）
		expiration = 1 * time.Hour
	}

	// 加入黑名单
	return AddTokenToBlacklist(refreshToken, expiration)
}

// AddTokenToBlacklist 将token加入黑名单（登出时使用）
// 使用token的哈希值存储，保护隐私
func AddTokenToBlacklist(accessToken string, expiration time.Duration) error {
	// 计算token的SHA256哈希
	hash := sha256.Sum256([]byte(accessToken))
	tokenHash := hex.EncodeToString(hash[:])

	expiresAt := time.Now().Add(expiration)

	blacklist := model.TokenBlacklist{
		TokenHash: tokenHash,
		ExpiresAt: expiresAt,
	}

	if err := config2.DB.Create(&blacklist).Error; err != nil {
		// 如果已存在，忽略错误（可能并发导致）
		if !errors.Is(err, gorm.ErrDuplicatedKey) {
			return fmt.Errorf("failed to add token to blacklist: %w", err)
		}
	}

	return nil
}

// IsTokenBlacklisted 检查token是否在黑名单中
func IsTokenBlacklisted(token string) (bool, error) {
	// 计算token的SHA256哈希
	hash := sha256.Sum256([]byte(token))
	tokenHash := hex.EncodeToString(hash[:])

	var count int64
	now := time.Now()

	// 查询是否存在且未过期
	if err := config2.DB.Model(&model.TokenBlacklist{}).
		Where("token_hash = ? AND expires_at > ?", tokenHash, now).
		Count(&count).Error; err != nil {
		return false, fmt.Errorf("failed to check token blacklist: %w", err)
	}

	return count > 0, nil
}

// CleanupExpiredTokens 清理过期的token黑名单（应该定期运行）
func CleanupExpiredTokens() error {
	now := time.Now()

	// 清理过期的token黑名单
	if err := config2.DB.Where("expires_at < ?", now).Delete(&model.TokenBlacklist{}).Error; err != nil {
		log.SystemLogger.Warn("failed to cleanup expired token blacklist", zap.Error(err))
	}

	return nil
}

// GenerateCSRFToken 生成无状态的CSRF token（使用HMAC签名）
func GenerateCSRFToken(userID int64) (string, error) {
	// 生成随机nonce
	nonceBytes := make([]byte, 16)
	if _, err := rand.Read(nonceBytes); err != nil {
		return "", fmt.Errorf("failed to generate nonce: %w", err)
	}
	nonce := hex.EncodeToString(nonceBytes)

	// 构建payload：userID:timestamp:nonce
	timestamp := time.Now().Unix()
	payload := fmt.Sprintf("%d:%d:%s", userID, timestamp, nonce)

	// 使用HMAC-SHA256签名
	mac := hmac.New(sha256.New, GetJWTSecret())
	mac.Write([]byte(payload))
	signature := hex.EncodeToString(mac.Sum(nil))

	// 返回 payload:signature（直接用字符串，不需要hex编码）
	csrfToken := fmt.Sprintf("%s:%s", payload, signature)
	return csrfToken, nil
}

// ValidateCSRFToken 验证CSRF token（无状态验证）
func ValidateCSRFToken(userID int64, csrfToken string) (bool, error) {
	// 分离payload和signature（最后一个冒号分隔）
	// 解码
	lastColonIdx := -1
	for i := len(csrfToken) - 1; i >= 0; i-- {
		if csrfToken[i] == ':' {
			lastColonIdx = i
			break
		}
	}
	if lastColonIdx == -1 {
		return false, errors.New("invalid CSRF token format")
	}

	payload := csrfToken[:lastColonIdx]
	signature := csrfToken[lastColonIdx+1:]

	// 验证HMAC签名
	mac := hmac.New(sha256.New, GetJWTSecret())
	mac.Write([]byte(payload))
	expectedSignature := hex.EncodeToString(mac.Sum(nil))

	if !hmac.Equal([]byte(signature), []byte(expectedSignature)) {
		return false, errors.New("invalid CSRF token signature")
	}

	// 解析payload: userID:timestamp:nonce
	var tokenUserID int64
	var timestamp int64
	var nonce string
	_, err := fmt.Sscanf(payload, "%d:%d:%s", &tokenUserID, &timestamp, &nonce)
	if err != nil {
		return false, fmt.Errorf("invalid CSRF token payload: %w", err)
	}

	// 验证用户ID
	if tokenUserID != userID {
		return false, errors.New("CSRF token user ID mismatch")
	}

	// 验证时间戳（CSRF token有效期24小时）
	tokenTime := time.Unix(timestamp, 0)
	if time.Since(tokenTime) > 24*time.Hour {
		return false, errors.New("CSRF token expired")
	}

	return true, nil
}

// GenerateShareToken 生成分享token（无状态JWT，有效期10分钟）
func GenerateShareToken(shareToken string) (string, error) {
	claims := jwt.MapClaims{
		"share_token": shareToken,
		"type":        "share",
		"exp":         time.Now().Add(10 * time.Minute).Unix(),
		"iat":         time.Now().Unix(),
		"iss":         "go-pan",
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(GetJWTSecret())
}

// ValidateShareToken 验证分享token并提取shareToken
func ValidateShareToken(shareTokenJWT string) (string, error) {
	token, err := jwt.Parse(shareTokenJWT, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return GetJWTSecret(), nil
	})

	if err != nil {
		return "", fmt.Errorf("failed to parse share token: %w", err)
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		// 验证 token 类型
		if tokenType, ok := claims["type"].(string); !ok || tokenType != "share" {
			return "", errors.New("invalid token type")
		}

		// 提取 share_token
		shareToken, ok := claims["share_token"].(string)
		if !ok {
			return "", errors.New("invalid share_token in token")
		}

		return shareToken, nil
	}

	return "", errors.New("invalid share token")
}
